//
//  BTReceiveDataManager.swift
//  TimeBoat
//
//  Created by Jun on 2022/9/7.
//  Copyright © 2022 Time Boat. All rights reserved.
//

import Foundation

@objc class BTLEReceiveDataManager: NSObject {
    @objc static let shared = BTLEReceiveDataManager()
    private let tag = LogTag.init(rawValue: "BTLEReceiveDataManager")
    
    private var mBufferLen: Int = 0
    private var mDataLen: Int = 0
    private var mBuffer = [UInt8]()
    private var mHasHeader = false
    private var mCmdTypeValid = false
    private var mLock = NSLock.init()
    
    override init() {
        super.init()
    }
    
    /**
     * 存在以下几种数据情况：
     * 1. 每次buf是完整的命令: 头 + 类型 + 数据长度 + 时间戳 + 数据内容
     * 2. buf前面有完整的命令，后面无效数据
     * 3. buf前面无效数据，后面有完整命令
     * 4. buf前面有完整命令，后面有下一个命令部分数据
     * 5. buf有多条完整命令
     * 6. buf前面有一条完整命令，中间有无效数据，后面又有多条完整命令
     * 7. 完整命令分成多次buf传入，最终解析成一条命令
     */
    @objc func parse(buf: [UInt8]?) -> [BLECMDItem]? {
        if (nil == buf) {
            return nil
        }
        
        var result: [BLECMDItem]? = nil
        mLock.lock()
        result = parseBuffer(buf: buf)
        mLock.unlock()
        
        return result
    }
    
    @objc func parseCmd(buf: [UInt8]?) {
        let cmdList = parse(buf: buf)
        if (nil != cmdList && !(cmdList!.isEmpty)) {
            cmdHandle(cmdList: cmdList)
        }
    }
    
    @objc func parseBuffer(buf: [UInt8]?) -> [BLECMDItem]? {
        if (nil == buf) {
            return nil
        }
        
        var cmdList = [BLECMDItem]()
        var c: UInt8 = 0
        for element in buf! {
            c = element
            if (mHasHeader) {
                // cmd type
                if (1 == mBufferLen) {
                    // cmd type 1
                    if (BTLECMDType.isCMDTypeValid(c: c)) {
                        mCmdTypeValid = true
                        mBuffer.append(c)
                        mBufferLen += 1
                    } else {
                        mHasHeader = false
                        mCmdTypeValid = false
                        mBufferLen = 0
                        mDataLen = 0
                    }
                } else if (2 == mBufferLen || 3 == mBufferLen) {
                    // data len 2/3
                    mBuffer.append(c)
                    mBufferLen += 1
                } else if (4 == mBufferLen) {
                    // timestamp 4/5/6/7
                    mBuffer.append(c)
                    mBufferLen += 1

                    mDataLen = Int(mBuffer[2] & 0xff) | ((Int(mBuffer[3] & 0xff) << 8))
                } else if (5 == mBufferLen || 6 == mBufferLen || 7 == mBufferLen) {
                    // timestamp 4/5/6/7
                    mBuffer.append(c)
                    mBufferLen += 1
                } else {
                    if (mDataLen > 0) {
                        mBuffer.append(c)
                        mBufferLen += 1

                        mDataLen -= 1
                    }

                    if (0 == mDataLen) {
                        let header = mBuffer[0]
                        let type = mBuffer[1]
                        let len = Int(mBuffer[2] & 0xff) | (Int(mBuffer[3] & 0xff) << 8)
                        let timestampSecond: Int = Int(mBuffer[4] & 0xff) | (Int(mBuffer[5] & 0xff) << 8) | (Int(mBuffer[6] & 0xff) << 16) | (Int(mBuffer[7] & 0xff) << 24)
                        var data: [UInt8] = [UInt8]()
                        if (len > 0) {
                            for i in 8...(mBufferLen-1) {
                                data.append(mBuffer[i])
                            }
                        }

                        let cmdItem = BLECMDItem(header: header, cmdType: type, dataLen: len, timestampSecond: timestampSecond, data: data)
                        cmdList.append(cmdItem)

                        mHasHeader = false
                        mBufferLen = 0
                        mCmdTypeValid = false
                        mDataLen = 0
                        mBuffer.removeAll()
                    }
                }
            } else {
                if (BTLECMDType.isHeader(c: c)) {
                    // header 0
                    mHasHeader = true
                    mBufferLen = 0
                    mBuffer.append(c)
                    mBufferLen += 1
                } else {
                    mHasHeader = false
                    mBufferLen = 0
                    mCmdTypeValid = false
                    mDataLen = 0
                    mBuffer.removeAll()
                }
            }
        }
        
        return cmdList
    }
    
    @objc func cmdHandle(cmdList: [BLECMDItem]?) {
        if (nil == cmdList && cmdList!.count <= 0) {
            return
        }
        
        for cmdItem in cmdList! {
            Log.debug(tag: tag, "cmd item = \(cmdItem.toString())")
            
            let type = cmdItem.cmdType
            let buffer = (nil != cmdItem.data) ? (cmdItem.data!) : [UInt8]()
            let deviceTimestampSecond = UInt32(cmdItem.timestampSecond)
            
            switch (type) {
            /// 计步数据
            case BTLECMDType.STEP_COUNT.rawValue:
                Log.debug(tag: tag, "STEP_COUNT")
                let model = StepCountDataModel(buf: buffer)
                Log.debug(tag: tag, "step count = " + model.toString())
                
                TCPSendDataManager.shared.sendStepCommand(deviceTimestampSecond: deviceTimestampSecond,
                                                          stepCount: model.step,
                                                          distance: model.distance,
                                                          cal: model.calorie)
                break
                
            /// 心率数据
            case BTLECMDType.HEART_RATE.rawValue:
                Log.debug(tag: tag, "MEASURE_HEART_RATE")
                let model = HeartRateDataModel(buf: buffer)
                Log.debug(tag: tag, "heart rate model = " + model.toString())
                
                TCPSendDataManager.shared.sendHeartRateCommand(deviceTimestampSecond: deviceTimestampSecond, heartRate: model.heartRate)
                break
                
            /// 睡眠监测数据
            case BTLECMDType.SLEEP.rawValue:
                Log.debug(tag: tag, "SLEEP")
                let model = SleepDataModel(buf: buffer, dataLength: buffer.count)
                Log.debug(tag: tag, "sleep model = " + model.toString())
                
                for sleepItem in model.sleepDataList {
                    TCPSendDataManager.shared.sendSleepCommand(deviceTimestampSecond: deviceTimestampSecond,
                                                               hour: UInt32(sleepItem.hour),
                                                               minute: UInt32(sleepItem.minute),
                                                               state: UInt32(sleepItem.state))
                }
                break
                
            ///  跑步运动数据
            case BTLECMDType.RUNNING.rawValue:
                Log.debug(tag: tag, "RUNNING")
                let model = RunDataModel(buf: buffer)
                Log.debug(tag: tag, "running model = " + model.toString())
                
                TCPSendDataManager.shared.sendRunCommand(deviceTimestampSecond: deviceTimestampSecond, model: model)
                break
                
            /// 马拉松训练数据
            case BTLECMDType.MARATHON.rawValue:
                Log.debug(tag: tag, "MARATHON")
                let model = RunDataModel(buf: buffer)
                Log.debug(tag: tag, "marathon model = " + model.toString())
                break
                
            /// 徒步运动数据
            case BTLECMDType.HIKING.rawValue:
                Log.debug(tag: tag, "HIKING")
                let model = HikingDataModel(buf: buffer)
                Log.debug(tag: tag, "hiking model = " + model.toString())
                
                TCPSendDataManager.shared.sendHikingCommand(deviceTimestampSecond: deviceTimestampSecond, model: model)
                break
                
            /// 跳绳运动数据
            case BTLECMDType.SKIPPING_ROPE.rawValue:
                Log.debug(tag: tag, "SKIPPING_ROPE")
                break
                
            /// 游泳运动数据
            case BTLECMDType.SWIM.rawValue:
                Log.debug(tag: tag, "SWIM")
                let model = SwimDataModel(buf: buffer)
                Log.debug(tag: tag, "swim model = " + model.toString())
                break
                
            /// 攀岩运动数据
            case BTLECMDType.ROCK_CLIMBING.rawValue:
                Log.debug(tag: tag, "ROCK_CLIMBING")
                let model = RockClimbingDataModel(buf: buffer)
                Log.debug(tag: tag, "rock climbing model = " + model.toString())
                break
                
            /// 滑雪运动数据
            case BTLECMDType.SKIING.rawValue:
                Log.debug(tag: tag, "SKIING")
                let model = SkiingDataModel(buf: buffer)
                Log.debug(tag: tag, "skiing model = " + model.toString())
                break
                
            /// 骑行运动数据
            case BTLECMDType.RIDE.rawValue:
                Log.debug(tag: tag, "RIDE")
                let model = RideDataModel(buf: buffer)
                Log.debug(tag: tag, "ride model = " + model.toString())
                
                TCPSendDataManager.shared.sendRideCommand(deviceTimestampSecond: deviceTimestampSecond, model: model)
                break
                
            /// 划船运动数据
            case BTLECMDType.BOAT.rawValue:
                Log.debug(tag: tag, "BOAT")
                let model = BoatDataModel(buf: buffer)
                Log.debug(tag: tag, "boat model = " + model.toString())
                break
                
            /// 蹦极运动数据
            case BTLECMDType.BUNGEE_JUMPING.rawValue:
                Log.debug(tag: tag, "BUNGEE_JUMPING")
                break
                
            /// 登山运动数据
            case BTLECMDType.MOUNTAINEERING.rawValue:
                Log.debug(tag: tag, "MOUNTAINEERING")
                let model = MountaineeringDataModel(buf: buffer)
                Log.debug(tag: tag, "mountainerring model = " + model.toString())
                
                TCPSendDataManager.shared.sendMountaineeringCommand(deviceTimestampSecond: deviceTimestampSecond, model: model)
                break
                
            /// 跳伞运动数据
            case BTLECMDType.PARACHUTE_JUMP.rawValue:
                Log.debug(tag: tag, "PARACHUTE_JUMP")
                break
                
            /// 高尔夫运动数据
            case BTLECMDType.GOLF.rawValue:
                Log.debug(tag: tag, "GOLF")
                let model = GolfDataModel(buf: buffer)
                Log.debug(tag: tag, "golf model = " + model.toString())
                break
                
            /// 冲浪运动数据
            case BTLECMDType.SURFING.rawValue:
                Log.debug(tag: tag, "SURFING")
                let model = SurfingDataModel(buf: buffer)
                Log.debug(tag: tag, "surfing model = " + model.toString())
                break
                
            /// 气压检测数据
            case BTLECMDType.BAROMETRIC_PRESSURE.rawValue:
                Log.debug(tag: tag, "BAROMETRIC_PRESSURE")
                let model = BarometricPressureDataModel(buf: buffer)
                Log.debug(tag: tag, "barometric pressureData model = " + model.toString())
                break
                
            /// SOS呼救
            case BTLECMDType.SOS.rawValue:
                Log.debug(tag: tag, "SOS")
                let model = SOSDataModel(buf: buffer)
                Log.debug(tag: tag, "sos model = " + model.toString())
                break
                
            /// 跑步机训练数据
            case BTLECMDType.RUNNING_MACHINE.rawValue:
                Log.debug(tag: tag, "RUNNING_MACHINE")
                let model = RunningMachineDataModel(buf: buffer)
                Log.debug(tag: tag, "running machine model = " + model.toString())
                
                TCPSendDataManager.shared.sendRunningMachineCommand(deviceTimestampSecond: deviceTimestampSecond, model: model)
                break
                
            /// 拍照
            case BTLECMDType.PICTURE.rawValue:
                Log.debug(tag: tag, "PICTURE")
                break
                
            /// 寻找手机
            case BTLECMDType.FIND_PHONE.rawValue:
                Log.debug(tag: tag, "FIND_PHONE")
                break
                
            /// 当前主动测量心率值
            case BTLECMDType.MEASURE_HEART_RATE.rawValue:
                Log.debug(tag: tag, "MEASURE_HEART_RATE")
                let model = HeartRateDataModel(buf: buffer)
                Log.debug(tag: tag, "heart rate model = " + model.toString())
                
                TCPSendDataManager.shared.sendHeartRateCommand(deviceTimestampSecond: deviceTimestampSecond, heartRate: model.heartRate)
                break
                
            /// 当前主动测量体温值
            case BTLECMDType.MEASURE_BODY_TEMPERATURE.rawValue:
                Log.debug(tag: tag, "MEASURE_BODY_TEMPERATURE")
                let model = BodyTemperatureDataModel(buf: buffer)
                Log.debug(tag: tag, "body temperature model = " + model.toString())
                
                TCPSendDataManager.shared.sendTempCommand(deviceTimestampSecond: deviceTimestampSecond, temp: model.bodyTempStr)
                break
                
            /// 总步数
            case BTLECMDType.TOTAL_STEP.rawValue:
                Log.debug(tag: tag, "TOTAL_STEP")
                let model = TotalStepsDataModel(buf: buffer)
                Log.debug(tag: tag, "total step model = " + model.toString())
                
                TCPSendDataManager.shared.sendTotalStepCommand(deviceTimestampSecond: deviceTimestampSecond,
                                                               stepCount: model.totalStep,
                                                               distance: model.totalDistance,
                                                               cal: model.totalCalorie)
                break
                
            /// 手表改变配置信息
            case BTLECMDType.CHANGE_CONFIG.rawValue:
                Log.debug(tag: tag, "CHANGE_CONFIG")
                break
                
            /// 羽毛球
            case BTLECMDType.BADMINTON.rawValue:
                Log.debug(tag: tag, "BADMINTON")
                let model = BallDataModel(buf: buffer)
                Log.debug(tag: tag, "badminton model = " + model.toString())
                
                TCPSendDataManager.shared.sendBadmintonCommand(deviceTimestampSecond: deviceTimestampSecond, model: model)
                break
                
            /// 篮球
            case BTLECMDType.BASKETBALL.rawValue:
                Log.debug(tag: tag, "BASKETBALL")
                let model = BallDataModel(buf: buffer)
                Log.debug(tag: tag, "basketball model = " + model.toString())
                
                TCPSendDataManager.shared.sendBasketballCommand(deviceTimestampSecond: deviceTimestampSecond, model: model)
                break
                
            /// 足球
            case BTLECMDType.FOOTBALL.rawValue:
                Log.debug(tag: tag, "FOOTBALL")
                let model = BallDataModel(buf: buffer)
                Log.debug(tag: tag, "football model = " + model.toString())
                
                TCPSendDataManager.shared.sendFootballCommand(deviceTimestampSecond: deviceTimestampSecond, model: model)
                break
                
            /// 主动测量的血氧值
            case BTLECMDType.BLOOD_OXYGEN.rawValue:
                Log.debug(tag: tag, "BLOOD_OXYGEN")
                let model = BloodOxygenDataModel(buf: buffer)
                Log.debug(tag: tag, "blood oxygen model = " + model.toString())
                
                TCPSendDataManager.shared.sendOxygenCommand(deviceTimestampSecond: deviceTimestampSecond, bloodOxygen: UInt32(model.bloodOxygen))
                break
                
            /// 时间同步
            case BTLECMDType.SYNC_TIME.rawValue:
                Log.debug(tag: tag, "SYNC_TIME")
                break
                
            /// 用户信息
            case BTLECMDType.USER_INFO.rawValue:
                Log.debug(tag: tag, "USER_INFO")
                break
                
            /// 设备信息
            case BTLECMDType.DEVICE_INFO.rawValue:
                Log.debug(tag: tag, "DEVICE_INFO")
                let model = DeviceInfoDataModel(buf: buffer)
                parseDeviceInfoCMD(deviceInfo: model)
                break
                
            /// 天气
            case BTLECMDType.WEATHER.rawValue:
                Log.debug(tag: tag, "WEATHER")
                break
                
            /// 来电提醒
            case BTLECMDType.CALL_REMINDER.rawValue:
                Log.debug(tag: tag, "CALL_REMINDER")
                break
                
            /// 断开连接命令
            case BTLECMDType.DISCONNECT.rawValue:
                Log.debug(tag: tag, "DISCONNECT")
                break
                
            /// 设置巡航坐标
            case BTLECMDType.CRUISE_COORDINATE.rawValue:
                Log.debug(tag: tag, "CRUISE_COORDINATE")
                break
                
            /// 寻找手表
            case BTLECMDType.FIND_WATCH.rawValue:
                Log.debug(tag: tag, "FIND_WATCH")
                break
                
            /// 同步语言
            case BTLECMDType.SYNC_LANGUAGE.rawValue:
                Log.debug(tag: tag, "SYNC_LANGUAGE")
                break
                
            /// 信息（短信、微信、QQ等）
            case BTLECMDType.MESSAGE.rawValue:
                Log.debug(tag: tag, "MESSAGE")
                break
                
            /// 设置单位制式
            case BTLECMDType.SET_UNIT.rawValue:
                Log.debug(tag: tag, "SET_UNIT")
                break
                
            /// iOS系统通知拦截配置
            case BTLECMDType.IOS_NOTIFICATION_CONFIG.rawValue:
                Log.debug(tag: tag, "IOS_NOTIFICATION_CONFIG")
                break
                
            /// 海拔校验数据
            case BTLECMDType.ALTITUDE_CALIBRATION.rawValue:
                Log.debug(tag: tag, "ALTITUDE_CALIBRATION")
                break
                
            /// 时间制式
            case BTLECMDType.TIME_UNIT.rawValue:
                Log.debug(tag: tag, "TIME_UNIT")
                break
                
            /// 设置主动测量心率
            case BTLECMDType.SET_HEART_RATE.rawValue:
                Log.debug(tag: tag, "SET_HEART_RATE")
                break
                
            /// 传输图片
            case BTLECMDType.TRANSFER_IMAGE.rawValue:
                Log.debug(tag: tag, "TRANSFER_IMAGE")
                break
                
            default:
                break
            }
        }
        
        NotificationCenter.default.postBTLEDidUpdateData(object: self, info: nil)
    }
    
    @objc func parseDeviceInfoCMD(deviceInfo: DeviceInfoDataModel?) {
        if (nil != deviceInfo) {
            let data: DeviceInfoDataModel = deviceInfo!

            if (data.stepCount > 0) {
                Log.debug(tag: tag, "need read step count data")
                sendCommand(buffer: BTLECMDType.buildStepCountCMDHeader())
            }

            if (data.heartRate > 0) {
                Log.debug(tag: tag, "need read heart rate data ")
                sendCommand(buffer: BTLECMDType.buildHeartRateCMDHeader())
            }

            if (data.sleep > 0) {
                Log.debug(tag: tag, "need read sleep data ")
                sendCommand(buffer: BTLECMDType.buildSleepCMDHeader())
            }

            if (data.run > 0) {
                Log.debug(tag: tag, "need read running data ")
                sendCommand(buffer: BTLECMDType.buildRunningCMDHeader())
            }

            if (data.hiking > 0) {
                Log.debug(tag: tag, "need read walk data ")
                sendCommand(buffer: BTLECMDType.buildHikingCMDHeader())
            }

            if (data.marathon > 0) {
                Log.debug(tag: tag, "need read marathon data ")
                sendCommand(buffer: BTLECMDType.buildMarathonCMDHeader())
            }

            if (data.skippingRope > 0) {
                Log.debug(tag: tag, "need read skippingRope data ")
                sendCommand(buffer: BTLECMDType.buildSkippingRopeCMDHeader())
            }

            if (data.swim > 0) {
                Log.debug(tag: tag, "need read swimming data ")
                sendCommand(buffer: BTLECMDType.buildSwimmingCMDHeader())
            }

            if (data.rockClimbing > 0) {
                Log.debug(tag: tag, "need read rockClimbing data ")
                sendCommand(buffer: BTLECMDType.buildRockClimbingCMDHeader())
            }

            if (data.skiing > 0) {
                Log.debug(tag: tag, "need read skiing data ")
                sendCommand(buffer: BTLECMDType.buildSkiingCMDHeader())
            }

            if (data.ride > 0) {
                Log.debug(tag: tag, "need ride data ")
                sendCommand(buffer: BTLECMDType.buildRideCMDHeader())
            }

            if (data.boat > 0) {
                Log.debug(tag: tag, "need boat data ")
                sendCommand(buffer: BTLECMDType.buildBoatCMDHeader())
            }

            if (data.bungeeJumping > 0) {
                Log.debug(tag: tag, "need bungeeJumping data ")
                sendCommand(buffer: BTLECMDType.buildBungeeJumpingCMDHeader())
            }

            if (data.mountaineering > 0) {
                Log.debug(tag: tag, "need mountaineering data ")
                sendCommand(buffer: BTLECMDType.buildMountaineeringCMDHeader())
            }

            if (data.parachuteJump > 0) {
                Log.debug(tag: tag, "need parachuteJump data ")
                sendCommand(buffer: BTLECMDType.buildParachuteJumpCMDHeader())
            }

            if (data.golf > 0) {
                Log.debug(tag: tag, "need golf data ")
                sendCommand(buffer: BTLECMDType.buildGolfCMDHeader())
            }

            if (data.surfing > 0) {
                Log.debug(tag: tag, "need surfing data ")
                sendCommand(buffer: BTLECMDType.buildSurfingCMDHeader())
            }

            if (data.runningMachine > 0) {
                Log.debug(tag: tag, "need runTraining data ")
                sendCommand(buffer: BTLECMDType.buildRunTrainingCMDHeader())
            }

            if (data.measureHeartRate > 0) {
                Log.debug(tag: tag, "need measureHeartRate data ")
                sendCommand(buffer: BTLECMDType.buildMeasureHeartRateCMDHeader())
            }

            if (data.bleAddress?.isEmpty ?? false) {
                Log.debug(tag: tag, "Bluetooth Address = " + String.toHexStr(buf: data.bleAddress))
            }

            if (data.badminton > 0) {
                Log.debug(tag: tag, "need badminton data ")
                sendCommand(buffer: BTLECMDType.buildBadmintonCMDHeader())
            }

            if (data.basketball > 0) {
                Log.debug(tag: tag, "need basketball data ")
                sendCommand(buffer: BTLECMDType.buildBasketballCMDHeader())
            }

            if (data.footBall > 0) {
                Log.debug(tag: tag, "need footBall data ")
                sendCommand(buffer: BTLECMDType.buildFootballCMDHeader())
            }

            if (data.bloodOxygen > 0) {
                Log.debug(tag: tag, "need bloodOxygen data ")
                sendCommand(buffer: BTLECMDType.buildBloodOxygenCMDHeader())
            }
        }
    }
    
    private func sendCommand(buffer: [UInt8]) {
        BTLEBaseDataManager.shared.sendCommandBuffer(buffer: buffer)
    }
}
